package com.tsx.template.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsx.template.common.constants.ResultMessage;
import com.tsx.template.common.constants.StatusCode;
import com.tsx.template.common.dto.AuthAssignRoleDTO;
import com.tsx.template.common.dto.AuthUserAddDTO;
import com.tsx.template.common.dto.AuthUserLoginDTO;
import com.tsx.template.common.dto.AuthUserUpdateDTO;
import com.tsx.template.common.exception.BusinessException;
import com.tsx.template.common.vo.*;
import com.tsx.template.entity.AuthPermission;
import com.tsx.template.entity.AuthRole;
import com.tsx.template.entity.AuthUser;
import com.tsx.template.entity.AuthUserRole;
import com.tsx.template.mapper.AuthPermissionMapper;
import com.tsx.template.mapper.AuthRoleMapper;
import com.tsx.template.mapper.AuthUserMapper;
import com.tsx.template.mapper.AuthUserRoleMapper;
import com.tsx.template.service.AuthUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Xuan
 * @description 针对表【auth_user】的数据库操作Service实现
 * @createDate 2024-04-03 12:04:22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, AuthUser>
        implements AuthUserService {
    final AuthUserMapper authUserMapper;
    final AuthRoleMapper authRoleMapper;
    final AuthPermissionMapper authPermissionMapper;
    final AuthUserRoleMapper authUserRoleMapper;

    @Override
    public AuthUserLoginVO login(AuthUserLoginDTO authUserLoginDTO) {
        LambdaQueryWrapper<AuthUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(AuthUser::getUsername, authUserLoginDTO.getUsername());
        // 数据库的用户信息
        AuthUser authUserDB = authUserMapper.selectOne(lambdaQueryWrapper);
        if (Objects.isNull(authUserDB)) {
            throw new BusinessException(StatusCode.ERROR, ResultMessage.LOGIN_ERROR);
        }
        if (authUserDB.getStatus() == 0) {
            throw new BusinessException(StatusCode.ERROR, ResultMessage.LOGIN_LOCK);
        }
        // 对比密码
        // 前端密码加密对比
        String sha1Pwd = SaSecureUtil.sha1(authUserLoginDTO.getPassword());
        if (!authUserDB.getPassword().equals(sha1Pwd)) {
            throw new BusinessException(StatusCode.ERROR, ResultMessage.LOGIN_ERROR);
        }

        // 查看之前是否有旧登录
        String oldToken = StpUtil.getTokenValueByLoginId(authUserDB.getId());
        if (StringUtils.hasText(oldToken)) {
            log.info("存在旧token:{}", oldToken);
            StpUtil.logout(authUserDB.getId());
        }
        StpUtil.login(authUserDB.getId());
        String token = StpUtil.getTokenValue();
        return AuthUserLoginVO.builder().token(token).build();
    }

    @Override
    public AuthUserInfoVO info() {
        long loginId = StpUtil.getLoginIdAsLong();
        SaSession saSession = StpUtil.getSessionByLoginId(loginId);
        System.out.println("authRoleMapper.getRolesByUserId(loginId) = " + authRoleMapper.getRolesByUserId(loginId).stream()
                .map(AuthRole::getRemark).toList());
        return saSession.get("userInfo", () -> {
            // 查询用户信息
            AuthUser authUser = authUserMapper.selectById(loginId);
            // 查询用户的buttons
            List<AuthPermission> permissions = authPermissionMapper.getPermissionsByUserId(loginId);
            List<String> buttons = permissions.stream()
                    .filter(p -> p.getType() == 1)
                    .map(AuthPermission::getCode).toList();
            // 查询用户的routes
            List<String> routes = permissions.stream()
                    .filter(p -> p.getType() == 0)
                    .map(AuthPermission::getMenuUrl).toList();
            // 查询用户的roles
            List<String> roles = authRoleMapper.getRolesByUserId(loginId).stream()
                    .map(AuthRole::getRemark).toList();
            return AuthUserInfoVO.builder()
                    .nickName(authUser.getNickName())
                    .avatar(authUser.getAvatar())
                    .buttons(buttons)
                    .routes(routes)
                    .roles(roles).build();
        });
    }

    @Override
    public PageInfoResult<AuthUserPageItemVO> pageUser(int page, int limit, String username) {
        IPage<AuthUserPageItemVO> iPage = new Page<>(page, limit);
        IPage<AuthUserPageItemVO> pageInfo = authUserMapper.pageUserWithRoles(iPage, username);
        PageInfoResult<AuthUserPageItemVO> result = new PageInfoResult<>();
        result.setRecords(pageInfo.getRecords());
        result.setCurrent(pageInfo.getCurrent());
        result.setTotal(pageInfo.getTotal());
        return result;
    }

    @Override
    public void saveUser(AuthUser authUser) {
        String password = authUser.getPassword();
        // 要是有密码就加密
        if (StringUtils.hasText(password)) {
            String sha1Pwd = SaSecureUtil.sha1(password);
            authUser.setPassword(sha1Pwd);
        } else {
            authUser.setPassword(SaSecureUtil.sha1("123456"));
        }
        authUserMapper.insert(authUser);
    }

    @Override
    public void assignRole(AuthAssignRoleDTO authAssignRoleDTO) {
        // 先清空该用户的所有角色
        Long userId = authAssignRoleDTO.getUserId();
        authUserRoleMapper.deleteByUserId(userId);
        // 先判断有没有角色
        if (authAssignRoleDTO.getRoles().isEmpty()) {
            // 没有角色就只是清空
            return;
        }
        // 再构建对象进行加入
        List<AuthUserRole> authUserRoles = authAssignRoleDTO.getRoles().stream()
                .map(r -> new AuthUserRole(userId, r)).toList();
        // 批量插入
        authUserRoleMapper.insertBatchUserRole(authUserRoles);
    }

    @Override
    public AuthUserRoleVO queryUserWithRoles(Long userId) {
        return authUserRoleMapper.queryUserWithRoles(userId);
    }

    @Override
    public void resetPwd(Long id) {
        long loginId = StpUtil.getLoginIdAsLong();
        if (loginId == id) {
            throw new BusinessException(StatusCode.ERROR, ResultMessage.NOT_ACTION_USER);
        }
        AuthUser authUser = new AuthUser();
        authUser.setId(id);
        authUser.setPassword(SaSecureUtil.sha1("123456"));
        authUserMapper.updateById(authUser);
    }

    @Override
    @Transactional
    public void addUser(AuthUserAddDTO authUserAddDTO) {
        AuthUser authUser = new AuthUser();
        authUser.setUsername(authUserAddDTO.getUsername());
        authUser.setNickName(authUserAddDTO.getNickName());
        authUser.setAvatar(authUserAddDTO.getAvatar());
        authUser.setStatus(authUserAddDTO.getStatus());
        authUser.setPassword(SaSecureUtil.sha1(authUserAddDTO.getPassword()));
        authUserMapper.insert(authUser);
        Integer[] roles = authUserAddDTO.getRoles();
        if (roles.length == 0) {
            return;
        }
        List<AuthUserRole> authUserRoles = Arrays.stream(roles).map(rid -> new AuthUserRole(authUser.getId(), rid)).toList();
        authUserRoleMapper.insertBatchUserRole(authUserRoles);
    }

    @Override
    public void removeUserAndRoles(List<Long> ids) {
        // 先删除对应的用户
        authUserMapper.deleteBatchIds(ids);
        // 再删除用户对应的角色关系
        authUserRoleMapper.deleteByUserIds(ids);
    }

    @Override
    public void updateUserWithRole(AuthUserUpdateDTO authUserUpdateDTO) {
        Long userId = authUserUpdateDTO.getId();
        AuthUser authUser = new AuthUser();
        authUser.setId(authUserUpdateDTO.getId());
        authUser.setNickName(authUserUpdateDTO.getNickName());
        authUser.setAvatar(authUserUpdateDTO.getAvatar());
        authUser.setStatus(authUserUpdateDTO.getStatus());
        authUserMapper.updateById(authUser);
        if (authUserUpdateDTO.getRoles().length == 0) {
            return;
        }
        authUserRoleMapper.deleteByUserId(userId);
        List<AuthUserRole> authUserRoles = Arrays.stream(authUserUpdateDTO.getRoles()).map(rid -> new AuthUserRole(userId, rid)).toList();
        authUserRoleMapper.insertBatchUserRole(authUserRoles);
    }


}




